home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
HAM Radio 3.2
/
Ham Radio Version 3.2 (Chestnut CD-ROMs)(1993).ISO
/
packet
/
n17jsrc
/
icmpcmd.c
< prev
next >
Wrap
C/C++ Source or Header
|
1991-04-28
|
7KB
|
279 lines
/* ICMP-related user commands
* Copyright 1991 Phil Karn, KA9Q
*/
/* Mods by PA0GRI */
#include <stdio.h>
#include "global.h"
#include "icmp.h"
#include "ip.h"
#include "mbuf.h"
#include "netuser.h"
#include "internet.h"
#include "timer.h"
#include "socket.h"
#include "proc.h"
#include "session.h"
#include "cmdparse.h"
#include "commands.h"
static int doicmpec __ARGS((int argc, char *argv[],void *p));
static int doicmpstat __ARGS((int argc, char *argv[],void *p));
static int doicmptr __ARGS((int argc, char *argv[],void *p));
static void pingtx __ARGS((int s,void *ping1,void *p));
static void pinghdr __ARGS((struct session *sp,struct ping *ping));
static struct cmds Icmpcmds[] = {
"echo", doicmpec, 0, 0, NULLCHAR,
"status", doicmpstat, 0, 0, NULLCHAR,
"trace", doicmptr, 0, 0, NULLCHAR,
NULLCHAR
};
int Icmp_trace;
static int Icmp_echo = 1;
int
doicmp(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return subcmd(Icmpcmds,argc,argv,p);
}
static int
doicmpstat(argc,argv,p)
int argc;
char *argv[];
void *p;
{
register int i;
int lim;
/* Note that the ICMP variables are shown in column order, because
* that lines up the In and Out variables on the same line
*/
lim = NUMICMPMIB/2;
for(i=1;i<=lim;i++){
tprintf("(%2u)%-20s%10lu",i,Icmp_mib[i].name,
Icmp_mib[i].value.integer);
tprintf(" (%2u)%-20s%10lu\n",i+lim,Icmp_mib[i+lim].name,
Icmp_mib[i+lim].value.integer);
}
return 0;
}
static int
doicmptr(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setbool(&Icmp_trace,"ICMP tracing",argc,argv);
}
static int
doicmpec(argc,argv,p)
int argc;
char *argv[];
void *p;
{
return setbool(&Icmp_echo,"ICMP echo response accept",argc,argv);
}
/* Send ICMP Echo Request packets */
int
doping(argc,argv,p)
int argc;
char *argv[];
void *p;
{
struct proc *pinger = NULLPROC; /* Transmit process */
struct sockaddr_in from;
struct icmp icmp;
struct mbuf *bp;
int32 timestamp,rtt,abserr;
int s,fromlen;
struct ping ping;
struct session *sp;
memset((char *)&ping,0,sizeof(ping));
/* Allocate a session descriptor */
if((sp = ping.sp = newsession(argv[1],PING,0)) == NULLSESSION){
tprintf("Too many sessions\n");
return 1;
}
if((sp->s = s = socket(AF_INET,SOCK_RAW,IPPROTO_ICMP)) == -1){
tprintf("Can't create socket\n");
keywait(NULLCHAR,1);
freesession(sp);
return 1;
}
tprintf("Resolving %s... ",sp->name);
if((ping.target = resolve(sp->name)) == 0){
tprintf("Host %s unknown\n",sp->name);
keywait(NULLCHAR,1);
freesession(sp);
return 1;
}
if(argc > 2)
ping.len = atoi(argv[2]);
if(argc > 3)
ping.interval = atol(argv[3]);
/* Optionally ping a range of IP addresses */
if(argc > 4)
ping.incflag = 1;
if(ping.interval != 0){
pinger = newproc("pingtx",300,pingtx,s,&ping,NULL,0);
} else {
/* One shot ping; let echo_proc hook handle response.
* An ID of MAXINT16 will not be confused with a legal socket
* number, which is used to identify repeated pings
*/
pingem(s,ping.target,0,MAXINT16,ping.len);
freesession(sp);
return 0;
}
/* Now collect the replies */
pinghdr(sp,&ping);
for(;;){
fromlen = sizeof(from);
if(recv_mbuf(s,&bp,0,(char *)&from,&fromlen) == -1)
break;
ntohicmp(&icmp,&bp);
if(icmp.type != ICMP_ECHO_REPLY || icmp.args.echo.id != s){
/* Ignore other people's responses */
free_p(bp);
continue;
}
/* Get stamp */
if(pullup(&bp,(char *)×tamp,sizeof(timestamp))
!= sizeof(timestamp)){
/* The timestamp is missing! */
free_p(bp); /* Probably not necessary */
continue;
}
free_p(bp);
ping.responses++;
/* Compute round trip time, update smoothed estimates */
rtt = msclock() - timestamp;
abserr = (rtt > ping.srtt) ? (rtt-ping.srtt) : (ping.srtt-rtt);
if(ping.responses == 1){
/* First response, base entire SRTT on it */
ping.srtt = rtt;
ping.mdev = 0;
} else {
ping.srtt = (7*ping.srtt + rtt + 4) >> 3;
ping.mdev = (3*ping.mdev + abserr + 2) >> 2;
}
if((ping.responses % 20) == 0)
pinghdr(sp,&ping);
tprintf("%10lu%10lu%5lu%10lu%10lu%10lu\n",
ping.sent,ping.responses,
(ping.responses*100 + ping.sent/2)/ping.sent,
rtt,ping.srtt,ping.mdev);
}
if(pinger != NULLPROC)
killproc(pinger);
freesession(sp);
return 0;
}
static void
pinghdr(sp,ping)
struct session *sp;
struct ping *ping;
{
tprintf("Pinging %s (%s); data %d interval %lu ms:\n",
sp->name,inet_ntoa(ping->target),ping->len,ping->interval);
tprintf(" sent rcvd % rtt avg rtt mdev\n");
}
void
echo_proc(source,dest,icmp,bp)
int32 source;
int32 dest;
struct icmp *icmp;
struct mbuf *bp;
{
int32 timestamp,rtt;
if(Icmp_echo && icmp->args.echo.id == MAXINT16
&& pullup(&bp,(char *)×tamp,sizeof(timestamp))
== sizeof(timestamp)){
/* Compute round trip time */
rtt = msclock() - timestamp;
tprintf("%s: rtt %lu\n",inet_ntoa(source),rtt);
}
free_p(bp);
}
/* Ping transmit process. Runs until killed */
static void
pingtx(s,ping1,p)
int s; /* Socket to use */
void *ping1;
void *p;
{
struct ping *ping;
ping = (struct ping *)ping1;
ping->sent = 0;
if(ping->incflag){
for(;;){
pingem(s,ping->target++,0,MAXINT16,ping->len);
ping->sent++;
pause(ping->interval);
}
} else {
for(;;){
pingem(s,ping->target,(int16)ping->sent++,(int16)s,ping->len);
pause(ping->interval);
}
}
}
/* Send ICMP Echo Request packet */
int
pingem(s,target,seq,id,len)
int s; /* Raw socket on which to send ping */
int32 target; /* Site to be pinged */
int16 seq; /* ICMP Echo Request sequence number */
int16 id; /* ICMP Echo Request ID */
int16 len; /* Length of optional data field */
{
struct mbuf *data;
struct mbuf *bp;
struct icmp icmp;
struct sockaddr_in to;
int32 clock;
clock = msclock();
data = ambufw((int16)(len+sizeof(clock)));
data->cnt = len+sizeof(clock);
/* Set optional data field, if any, to all 55's */
if(len != 0)
memset(data->data+sizeof(clock),0x55,len);
/* Insert timestamp and build ICMP header */
memcpy(data->data,(char *)&clock,sizeof(clock));
icmpOutEchos++;
icmpOutMsgs++;
icmp.type = ICMP_ECHO;
icmp.code = 0;
icmp.args.echo.seq = seq;
icmp.args.echo.id = id;
if((bp = htonicmp(&icmp,data)) == NULLBUF){
free_p(data);
return 0;
}
to.sin_family = AF_INET;
to.sin_addr.s_addr = target;
send_mbuf(s,bp,0,(char *)&to,sizeof(to));
return 0;
}